/*

 * Created on 2005-10-28
 *
 */
package bma.common.langutil.core;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串工具类
 * 
 * @author 关中
 * @since 1.0 (imported from BMA.ESP Project)
 * 
 */
public class StringUtil {

	/**
	 * 把字符串的第一个字符变为大写
	 * 
	 * @param str
	 * @return
	 */
	public static String cap(String str) {
		if (str == null) {
			return null;
		}
		if (str.length() == 1) {
			return str.toUpperCase();
		}
		return Character.toUpperCase(str.charAt(0)) + str.substring(1);
	}

	public static String uncap(String str) {
		if (str == null) {
			return null;
		}
		if (str.length() == 1) {
			return str.toLowerCase();
		}
		return Character.toLowerCase(str.charAt(0)) + str.substring(1);
	}

	public static String text2html(String text) {
		if (text == null) {
			return null;
		}
		String[] se = { "<", ">", "(\r\n|\n\r|\n|\r)", "\t", "  " };
		String[] rp = { "&lt;", "&gt;", "\n<br>", "&nbsp;&nbsp;&nbsp;&nbsp;",
				"&nbsp; " };
		for (int i = 0; i < se.length; i++) {
			text = text.replaceAll(se[i], rp[i]);
		}
		return text;
	}

	public static String ln2br(String text) {
		if (text == null) {
			return null;
		}
		return text.replaceAll("(\r\n|\n\r|\n|\r)", "\n<br>");
	}

	public static String[] tokenSplit(String source, String delim) {
		return tokenSplit(source, delim, false);
	}

	public static String[] tokenSplit(String source, String delim,
			boolean returnDelim) {
		StringTokenizer st = new StringTokenizer(source, delim, returnDelim);
		String[] r = new String[st.countTokens()];
		for (int i = 0; st.hasMoreTokens(); i++) {
			r[i] = st.nextToken();
		}
		return r;
	}

	public static String replaceHTML(String text) {
		return text.replaceAll("<", "&lt;").replace(">", "&gt;");
	}

	public static String trim(String str) {
		return str == null ? null : str.trim();
	}

	public static String text2js(String s) {
		if (s == null) {
			return null;
		}
		String[] se = { "\\\\", "\"", "(\r\n|\n\r|\n|\r)" };
		String[] rp = { "\\\\\\\\", "\\\\\"", "\\\\n" };
		for (int i = 0; i < se.length; i++) {
			s = s.replaceAll(se[i], rp[i]);
		}
		return s;
	}

	public static String sureEndString(String str, String lastString) {
		if (str == null) {
			return null;
		}
		if (ValueUtil.empty(lastString)) {
			return str;
		}
		if (str.endsWith(lastString)) {
			return str;
		}
		return str + lastString;
	}

	public static void sureEndString(StringBuffer buf, String lastString) {
		if (buf == null) {
			return;
		}
		if (ValueUtil.empty(lastString)) {
			return;
		}
		int sz = buf.length();
		int idx = buf.indexOf(lastString, sz - lastString.length());
		if (idx == -1) {
			buf.append(lastString);
		}
	}

	public static String[] regexSplit(String content, String regex) {
		if (content == null) {
			return null;
		}
		return content.split(regex);
	}

	public static List<String> strSplit(String content, String str) {
		if (content == null) {
			return null;
		}
		List<String> s = new LinkedList<String>();

		if (ValueUtil.empty(str)) {
			s.add(content);
		} else {
			int start = 0;
			int idx = content.indexOf(str, start);
			while (idx != -1) {
				s.add(content.substring(start, idx));
				start = idx + str.length();
				idx = content.indexOf(str, start);
			}
			if (start <= content.length()) {
				s.add(content.substring(start));
			}
		}
		return s;
	}

	public static boolean equals(String v1, String v2) {
		return ObjectUtil.equals(v1, v2);
	}

	public static boolean equalsIgnoreCase(String v1, String v2) {
		if (v1 == null) {
			return v2 == null;
		}
		return v1.equalsIgnoreCase(v2);
	}

	public static int indexOfIgnoreCase(String str1, String str2, int fromIndex) {
		if (str1 == null) {
			return -1;
		}
		if (str2 == null) {
			return -1;
		}
		int sourceCount = str1.length();
		int targetCount = str2.length();
		int sourceOffset = 0;
		int targetOffset = 0;

		if (fromIndex >= sourceCount) {
			return (targetCount == 0 ? sourceCount : -1);
		}
		if (fromIndex < 0) {
			fromIndex = 0;
		}
		if (targetCount == 0) {
			return fromIndex;
		}

		char first = Character.toLowerCase(str2.charAt(targetOffset));
		int max = sourceOffset + (sourceCount - targetCount);

		for (int i = sourceOffset + fromIndex; i <= max; i++) {
			/* Look for first character. */
			if (Character.toLowerCase(str1.charAt(i)) != first) {
				while (++i <= max && str1.charAt(i) != first) {
					;
				}
			}

			/* Found first character, now look at the rest of v2 */
			if (i <= max) {
				int j = i + 1;
				int end = j + targetCount - 1;
				for (int k = targetOffset + 1; j < end
						&& Character.toLowerCase(str1.charAt(j)) == Character
								.toLowerCase(str2.charAt(k)); j++, k++) {
					;
				}

				if (j == end) {
					/* Found whole string. */
					return i - sourceOffset;
				}
			}
		}
		return -1;
	}

	public static Pattern commonPatternToRegexPattern(String pattern) {
		return commonPatternToRegexPattern(pattern, false);
	}

	public static Pattern commonPatternToRegexPattern(String pattern,
			boolean group) {
		int length = pattern.length();

		StringBuffer cb = new StringBuffer();
		cb.append("^");
		for (int i = 0; i < length; i++) {
			char ch = pattern.charAt(i);

			if (ch == '*') {
				if (group) {
					cb.append("(.*)");
				} else {
					cb.append(".*");
				}
				continue;
			}
			if (ch == '.' || ch == '[' || ch == '^' || ch == '$' || ch == '{'
					|| ch == '}' || ch == '|' || ch == '(' || ch == ')'
					|| ch == '?') {
				cb.append('\\');
				cb.append(ch);
			} else {
				cb.append(ch);
			}
		}
		cb.append("\\z");

		return Pattern.compile(cb.toString());

	}

	public static String patternParse(Pattern pattern, String org, String format) {
		Matcher m = pattern.matcher(org);
		if (!m.matches())
			return null;
		StringBuffer sb = new StringBuffer();
		m.appendReplacement(sb, format);
		return sb.toString();
	}

	public static String extractString(String text) {
		// StringBuffers are an efficient way to modify strings
		StringBuffer sb = new StringBuffer(text);
		// Process character escapes
		int startPoint = 1; // skip initial quotation mark
		for (;;) {
			int slashIndex = sb.indexOf("\\", startPoint); // search for a
			// single backslash
			if (slashIndex == -1) {
				break;
			}
			// Else, we have a backslash
			char escapeType = sb.charAt(slashIndex + 1);
			switch (escapeType) {
			case 'u':
				// Unicode escape.
				String unicode = extractUnicode(sb, slashIndex);
				sb.replace(slashIndex, slashIndex + 6, unicode); // backspace
				break; // back to the loop

			// note: Java's character escapes match JSON's, which is why
			// it looks like we're replacing
			// "\b" with "\b". We're actually replacing 2 characters
			// (slash-b) with one (backspace).
			case 'b':
				sb.replace(slashIndex, slashIndex + 2, "\b"); // backspace
				break;

			case 't':
				sb.replace(slashIndex, slashIndex + 2, "\t"); // tab
				break;

			case 'n':
				sb.replace(slashIndex, slashIndex + 2, "\n"); // newline
				break;

			case 'f':
				sb.replace(slashIndex, slashIndex + 2, "\f"); // form feed
				break;

			case 'r':
				sb.replace(slashIndex, slashIndex + 2, "\r"); // return
				break;

			case '\'':
				sb.replace(slashIndex, slashIndex + 2, "\'"); // single
				// quote
				break;

			case '\"':
				sb.replace(slashIndex, slashIndex + 2, "\""); // double
				// quote
				break;
			case '\\':
				sb.replace(slashIndex, slashIndex + 2, "\\"); // backslash
				break;

			}
			startPoint = slashIndex + 1;

		}

		// remove surrounding quotes
		sb.deleteCharAt(0);
		sb.deleteCharAt(sb.length() - 1);

		return sb.toString();
	}

	public static String extractUnicode(StringBuffer sb, int slashIndex) {
		// Gather the 4 hex digits, convert to an integer, translate the number
		// to a unicode char, replace
		String result;
		String code = sb.substring(slashIndex + 2, slashIndex + 6);
		int charNum = Integer.parseInt(code, 16); // hex to integer
		// There's no simple way to go from an int to a unicode character.
		// We'll have to pass this through an output stream writer to do
		// the conversion.
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8");
			osw.write(charNum);
			osw.flush();
			result = baos.toString("UTF-8"); // Thanks to Silvester Pozarnik
			// for the tip about adding
			// "UTF-8"
		} catch (Exception e) {
			e.printStackTrace();
			result = null;
		}
		return result;
	}

	/**
	 * * 字符串转换成十六进制值 *
	 * 
	 * @param bin
	 *            String 我们看到的要转换成十六进制的字符串 *
	 * @return
	 */
	private final static char[] digit = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	public static String byte2Hex(byte[] data) {
		StringBuffer buf = new StringBuffer(data.length * 2);
		for (byte ib : data) {
			buf.append(digit[(ib >>> 4) & 0x0F]);
			buf.append(digit[ib & 0x0F]);
		}
		return buf.toString();
	}

	/**
	 * * 字符串转java字节码 *
	 * 
	 * @param b
	 *            *
	 * @return
	 */

	public static byte[] hex2byte(String s) {
		if (s == null)
			return null;
		if (s.isEmpty())
			return null;
		int len = s.length();

		byte[] rb = new byte[len / 2];
		char[] rc = s.toCharArray();
		for (int i = 0, j = 0; i < rc.length; i += 2, j++) {
			rb[j] = (byte) (((hexValue(rc[i]) << 4) + hexValue(rc[i + 1])) & 0xFF);
		}
		return rb;
	}

	public static String join(List<?> slist, String sp) {
		if (slist == null)
			return null;
		StringBuffer buf = new StringBuffer(200);
		Iterator<?> it = slist.iterator();
		while (it.hasNext()) {
			buf.append(it.next());
			if (it.hasNext())
				buf.append(sp);
		}
		return buf.toString();
	}

	public static int length(String path) {
		if (path == null)
			return 0;
		return path.length();
	}

	private static int hexValue(char c) {
		switch (c) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			return c - '0';
		case 'a':
		case 'A':
			return 10;
		case 'b':
		case 'B':
			return 11;
		case 'c':
		case 'C':
			return 12;
		case 'd':
		case 'D':
			return 13;
		case 'e':
		case 'E':
			return 14;
		case 'f':
		case 'F':
			return 15;
		default:
			throw new IllegalArgumentException("invalid HEX code '" + (int) c
					+ "'");
		}
	}

	public static String md5(byte[] data) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new UnsupportedOperationException("md5", e);
		}
		md.update(data);
		byte md5[] = md.digest();
		return byte2Hex(md5);
	}

}
